#pragma once

#include "Structs.h"
#include "Utils.h"
#include <pcl/point_types.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/range_image/range_image.h>
#include <pcl/kdtree/kdtree.h>
#include <pcl/features/normal_3d_omp.h>

#ifdef _WIN32
#ifdef ISCLIBLIDAR_EXPORTS
#define ISCLIBLIDAR_API __declspec(dllexport)
#elif defined(DEMO_BUILD)
#define ISCLIBLIDAR_API  // 在demo模式下不使用导入/导出
#else
#define ISCLIBLIDAR_API __declspec(dllimport)
#endif
#else
#define ISCLIBLIDAR_API
#endif

class ISCLIBLIDAR_API PointCloudHandler
{
public:
    /// @brief  @brief 离群点去除
    /// @param cloud
    /// @param meanK
    /// @param threshold
    /// @return
    static pcl::PointCloud<pcl::PointXYZI>::Ptr GetFilteredCloud(pcl::PointCloud<pcl::PointXYZI>::Ptr cloud, int meanK = 50, float threshold = 1.0, bool use_cuda = false);

    /// @brief 下采样
    /// @param cloud
    /// @param voxelW
    /// @param voxelL
    /// @param voxelH
    /// @return
    static pcl::PointCloud<pcl::PointXYZI>::Ptr GetDownSampledCloud(pcl::PointCloud<pcl::PointXYZI>::Ptr cloud, float voxelW = 0.01f, float voxelL = 0.01f, float voxelH = 0.01f, bool use_cuda = false);

    /// @brief 均匀采样
    /// @param cloud
    /// @param voxel
    /// @return
    static pcl::PointCloud<pcl::PointXYZI>::Ptr GetUniformSampledCloud(pcl::PointCloud<pcl::PointXYZI>::Ptr cloud, float voxel = 0.01f);

    /// @brief 点云数据变换
    /// @param cloud
    /// @param param
    /// @return
    static pcl::PointCloud<pcl::PointXYZI>::Ptr GetTransformCloud(pcl::PointCloud<pcl::PointXYZI>::Ptr cloud, TransformParam param);

    /// @brief 获取深度图
    /// @param cloud 点云数据
    /// @return 深度图
    static pcl::RangeImage::Ptr GetDepthImage(pcl::PointCloud<pcl::PointXYZI>::Ptr cloud);

    /// @brief 获取Narf关键点
    /// @param range_image 深度图
    /// @return narf关键点集合
    static pcl::PointCloud<pcl::PointXYZ>::Ptr GetNarfKeypoints(pcl::RangeImage::Ptr range_image);

    /// @brief 提取岸线-点集
    /// @param range_image
    /// @return
    static std::vector<pcl::PointCloud<pcl::PointXYZI>::Ptr> GetShoreLinePoints(pcl::RangeImage::Ptr range_image);

    /// @brief 提取岸线-直线
    /// @param range_image
    /// @return
    static std::vector<pcl::PointCloud<pcl::PointXYZ>::Ptr> GetShoreLinePolyLine(pcl::RangeImage::Ptr range_image);

    /// @brief 提取点云法线
    /// @param estimate_cloud 寻找临近点点云
    /// @param search_cloud 提取发现点云
    /// @param k_search 临近点个数
    /// @return
    static pcl::PointCloud<pcl::Normal>::Ptr GetNormalCloud(pcl::PointCloud<pcl::PointXYZI>::Ptr estimate_cloud, pcl::PointCloud<pcl::PointXYZI>::Ptr search_cloud = nullptr, int k_search = 10);

    static pcl::PointCloud<pcl::PointXYZI>::Ptr GetLinePlanOutSac(pcl::PointCloud<pcl::PointXYZI>::Ptr cloud, pcl::RangeImage::Ptr range_image);

    static pcl::PointCloud<pcl::PointXYZI>::Ptr GetLinePlanInSac(pcl::PointCloud<pcl::PointXYZI>::Ptr cloud, pcl::RangeImage::Ptr range_image);

    static std::vector<pcl::PointCloud<pcl::PointXYZ>::Ptr> GetShoreLinePolyLineEX(pcl::RangeImage::Ptr range_image);

    static std::vector<pcl::PointIndices> GetKdtreeCluster(pcl::PointCloud<pcl::PointXYZI>::Ptr cloud, double tolerance = 3, int min_size = 100, int max_size = 25000);

    static void sortPointCloudByY(pcl::PointCloud<pcl::PointXYZI>::Ptr cloud, bool ascending = true);
    static void sortPointCloudByIntensity(pcl::PointCloud<pcl::PointXYZI>::Ptr cloud, bool ascending = true);

    /// @brief 保存点云数据
    /// @param path 存储路径
    /// @param data 点云数据
    /// @return
    static bool SaveAsPCD(std::string path, pcl::PointCloud<pcl::PointXYZI>::Ptr data);

    /// @brief 保存点云数据为流数据
    /// @param path 存储路径
    /// @param data 点云数据
    /// @return
    static bool SaveAsStream(std::string path, pcl::PointCloud<pcl::PointXYZI>::Ptr data);
};